package net.jgrm.product.service.impl;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.alicp.jetcache.anno.CreateCache;
import com.baomidou.dynamic.datasource.annotation.DS;
import io.seata.core.context.RootContext;
import net.jgrm.product.mapper.ProductMapper;
import net.jgrm.product.service.IProductStockService;
import net.jgrm.redisadvanced.service.RedisStringService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

/**
 * 商品库存服务实现
 * 专门处理库存相关操作，采用分层缓存策略：
 * 1. Redis原子操作 - 秒杀场景的高并发写入
 * 2. JetCache本地缓存 - 读取加速
 * 3. 数据库 - 持久化存储
 *
 * @author jgrm
 */
@Service
public class ProductStockServiceImpl implements IProductStockService {

    private static final Logger logger = LoggerFactory.getLogger(ProductStockServiceImpl.class);
    private static final String STOCK_KEY_PREFIX = "product:stock:";
    private static final String PRE_STOCK_KEY_PREFIX = "product:pre_stock:";
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RedisStringService redisStringService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 库存本地缓存 - 短时间缓存，主要用于读取加速
     */
    @CreateCache(
            name = "product-stock",
            expire = 3000,  // 短时间缓存
            localExpire = 600,
            cacheType = CacheType.BOTH,
            syncLocal = true
    )
    private Cache<Long, Integer> stockCache;
    /**
     * 预减库存缓存 - 用于秒杀场景
     */
    @CreateCache(
            name = "product-pre-stock",
            expire = 3000,  // 短时间缓存
            localExpire = 600,
            cacheType = CacheType.REMOTE  // 只使用远程缓存，保证一致性
    )
    private Cache<Long, Integer> preStockCache;

    @Override
    @Cached(
            name = "product-stock",
            key = "#productId",
            expire = 300,  // 短时间缓存
            localExpire = 60,
            cacheType = CacheType.BOTH,
            syncLocal = true
    )
    @DS("slave1")
    public Integer getStock(Long productId) {
        logger.debug("Loading stock for product {} from database", productId);
        // 直接从数据库获取，不使用Redis缓存
        Integer stock = productMapper.getStockById(productId);
        return stock;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheInvalidate(name = "product-stock", key = "#productId")
    public boolean decreaseStock(Long productId, Integer quantity) {
        logger.info("Decreasing stock for product {} by {}", productId, quantity);
        // 更新数据库
        System.out.println("------------->" + RootContext.getXID());
        int rows = productMapper.decreaseStock(productId, quantity);
        if (rows > 0) {
            logger.info("Successfully decreased database stock for product {} by {}, affected rows: {}", productId, quantity, rows);
            // 删除Redis缓存，让后续查询从数据库重新加载
            removeGoodsStockRedisCache(productId);
            return true;
        } else {
            logger.warn("Database stock decrease failed for product {}, insufficient stock or product not found", productId);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheInvalidate(name = "product-stock", key = "#productId")
    public boolean increaseStock(Long productId, Integer quantity) {
        logger.info("Increasing stock for product {} by {}", productId, quantity);

        // 更新数据库
        int rows = productMapper.increaseStock(productId, quantity);
        if (rows > 0) {
            // 删除Redis缓存
            removeGoodsStockRedisCache(productId);
            logger.info("Successfully increased database stock for product {} by {}", productId, quantity);
            return true;
        }
        return false;
    }

    /**
     * 删除商品库存Redis缓存
     *
     * @param productId
     */
    private void removeGoodsStockRedisCache(Long productId) {
        try {
            String stockKey = STOCK_KEY_PREFIX + productId;
            redisTemplate.delete(stockKey);
            logger.info("Deleted Redis cache for product {} after database update", productId);
        } catch (Exception e) {
            logger.error("Error deleting Redis cache for product {}", productId, e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheInvalidate(name = "product-stock", key = "#productId")
    public boolean setStock(Long productId, Integer stock) {
        logger.info("Setting stock for product {} to {}", productId, stock);

        // 更新数据库
        int rows = productMapper.updateStock(productId, stock);
        if (rows > 0) {
            // 删除Redis缓存
            removeGoodsStockRedisCache(productId);
            logger.info("Successfully set database stock for product {} to {}", productId, stock);
            return true;
        }
        return false;
    }

    @Override
    public Integer preDecrease(Long productId, Integer quantity) {
        logger.info("Pre-decreasing stock for product {} by {} (seckill scenario)", productId, quantity);

        String preStockKey = PRE_STOCK_KEY_PREFIX + productId;

        // 首次预减时，从实际库存初始化
        if (redisStringService.get(preStockKey, String.class) == null) {
            Integer actualStock = getStock(productId);
            if (actualStock == null || actualStock <= 0) {
                return -1;
            }
            redisStringService.set(preStockKey, actualStock, 600, TimeUnit.SECONDS);
        }

        // 原子预减操作
        Long newPreStock = redisStringService.decrement(preStockKey, quantity);

        if (newPreStock != null && newPreStock >= 0) {
            logger.debug("Pre-decreased stock for product {} to {}", productId, newPreStock);
            return newPreStock.intValue();
        } else {
            // 库存不足，恢复
            if (newPreStock != null && newPreStock < 0) {
                redisStringService.increment(preStockKey, quantity);
            }
            return -1;
        }
    }

    @Override
    public void restorePreDecrease(Long productId, Integer quantity) {
        logger.info("Restoring pre-decreased stock for product {} by {}", productId, quantity);

        String preStockKey = PRE_STOCK_KEY_PREFIX + productId;
        redisStringService.increment(preStockKey, quantity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmPreDecrease(Long productId, Integer quantity) {
        logger.info("Confirming pre-decreased stock for product {} by {}", productId, quantity);

        // 确认预减，真正扣减数据库库存
        decreaseStock(productId, quantity);
    }

    @Override
    @CacheInvalidate(name = "product-stock", key = "#productId")
    public void refreshStockCache(Long productId) {
        logger.info("Refreshing stock cache for product {}", productId);

        // 删除Redis缓存
        String stockKey = STOCK_KEY_PREFIX + productId;
        redisTemplate.delete(stockKey);
    }

    @Override
    public void warmupStockCache(Long... productIds) {
        logger.info("Warming up stock cache for {} products", productIds.length);

        for (Long productId : productIds) {
            try {
                // 删除Redis缓存，让后续查询从数据库加载
                String stockKey = STOCK_KEY_PREFIX + productId;
                redisTemplate.delete(stockKey);
                logger.debug("Cleared cache for product {}", productId);
            } catch (Exception e) {
                logger.error("Failed to clear cache for product {}", productId, e);
            }
        }

        logger.info("Stock cache cleanup completed");
    }


}
